#include "helper.h"
#include "monitor.h"
#include "reg.h"

#define IMM_EXTEND 0xFFFF0000		// 立即数有符号扩展
#define IMM_SIGN_MASK 0x00008000	// 立即数符号位掩码
#define REG_MASK 0xFFFFFFFF			// 32位寄存器掩码

extern uint32_t instr;
extern char assembly[80];

/* decode I-type instrucion with unsigned immediate */
static void decode_imm_type(uint32_t instr) {

	op_src1->type = OP_TYPE_REG;
	op_src1->reg = (instr & RS_MASK) >> (RT_SIZE + IMM_SIZE);
	op_src1->val = reg_w(op_src1->reg);
	
	op_src2->type = OP_TYPE_IMM;
	op_src2->imm = instr & IMM_MASK;
	op_src2->val = op_src2->imm;

	op_dest->type = OP_TYPE_REG;
	op_dest->reg = (instr & RT_MASK) >> (IMM_SIZE);
}

make_helper(addi) {

	decode_imm_type(instr);
	if(op_src2->val & IMM_SIGN_MASK) op_src2->val |= IMM_EXTEND;
	long tmp = (op_src1->val) + (op_src2->val);
	if((tmp ^ op_src1->val) < 0 && (tmp ^ op_src2->val) < 0){
		// Overflow
		
	}
	else{
		reg_w(op_dest->reg) = tmp;
	}
	sprintf(assembly, "addi   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
}

make_helper(addiu) {

	decode_imm_type(instr);
	if(op_src2->val & IMM_SIGN_MASK) op_src2->val |= IMM_EXTEND;
	reg_w(op_dest->reg) = (op_src1->val + op_src2->val);
	sprintf(assembly, "addiu   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
}

make_helper(slti) {

	decode_imm_type(instr);
	if(op_src2->val & IMM_SIGN_MASK) op_src2->val |= IMM_EXTEND;
	reg_w(op_dest->reg) = (op_src1->val < op_src2->val) ? 1 : 0;
	sprintf(assembly, "slti   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
}

make_helper(sltiu) {

	decode_imm_type(instr);
	if(op_src2->val & IMM_SIGN_MASK) op_src2->val |= IMM_EXTEND;
	reg_w(op_dest->reg) = ((unsigned)(op_src1->val) < (unsigned)(op_src2->val)) ? 1 : 0;
	sprintf(assembly, "sltiu   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
 }

 make_helper(andi) {

	decode_imm_type(instr);
	reg_w(op_dest->reg) = (op_src1->val & op_src2->val);
	sprintf(assembly, "andi   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
 }

make_helper(lui) {

	decode_imm_type(instr);
	reg_w(op_dest->reg) = (op_src2->val << 16);
	sprintf(assembly, "lui   %s,   0x%04x", REG_NAME(op_dest->reg), op_src2->imm);
}

make_helper(ori) {

	decode_imm_type(instr);
	reg_w(op_dest->reg) = op_src1->val | op_src2->val;
	sprintf(assembly, "ori   %s,   %s,   0x%04x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
}

make_helper(xori) {

	decode_imm_type(instr);
	reg_w(op_dest->reg) = (op_src1->val ^ op_src2->val);
	sprintf(assembly, "xori   %s,   %s,   0x%04x", REG_NAME(op_dest->reg), REG_NAME(op_src1->reg), op_src2->imm);
}


